package com.yudaob2b.elong.task;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.yudaob2b.business.entity.po.ElongHotelInventoryPO;
import com.yudaob2b.business.service.ElongHotelInventoryService;
import com.yudaob2b.common.utils.DateUtil;
import com.yudaob2b.elong.constant.RedisConstant;
import com.yudaob2b.elong.entity.vo.IncrInventory;
import com.yudaob2b.elong.entity.vo.result.HotelIncrIdResult;
import com.yudaob2b.elong.entity.vo.result.HotelIncrInvResult;
import com.yudaob2b.elong.enums.EnumIncrType;
import com.yudaob2b.elong.service.HotelInventoryService;
import com.yudaob2b.elong.service.HttpStaticService;
import com.yudaob2b.elong.service.RedisPublisherService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 国内酒店-库存增量线程
 *
 * @author Kidd.Tan
 * @email 298023780@qq.com
 * @date 7/14/18 11:24 PM
 */
@Component
public class IncrInvProducerTask {
    private static Logger incrInvLogger = LoggerFactory.getLogger("incrInvLogger");
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private HttpStaticService httpStaticService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisPublisherService redisPublisherService;

    @Autowired
    private ElongHotelInventoryService elongHotelInventoryService;

    @Autowired
    private HotelInventoryService hotelInventoryService;

    /**
     * 国内酒店-库存增量生产者
     *
     * @throws InterruptedException
     */
    @Async("incrTaskExecutor")
    public void incrInvProducer() {
        String incrInvLastIdStr = "";
        Date lastTime = null;
        while (true) {
            try {
                //incrInvLogger.info("启动艺龙国内酒店－库存增量生产者，开始时间：{} ", DateUtil.format(new Date(), DateUtil.PATTERN_CLASSICAL));

                long start = System.currentTimeMillis();
                Object incrInvLastIdObj = redisTemplate.opsForValue().get(RedisConstant.REDIS_INCR_INV_LASTID_KEY);
                if (incrInvLastIdObj == null) {
                    // 最后的更新ID为空，通过接口查询最新的最后的更新ID
                    lastTime = new Date();
                    Object updateTimeObj = redisTemplate.opsForValue().get(RedisConstant.REDIS_INCR_INV_UPDATE_TIME_KEY);
                    if (updateTimeObj != null) {
                        lastTime = (Date) updateTimeObj;
                    }
                    HotelIncrIdResult hotelIncrIdResult = httpStaticService.getHotelIncrId(lastTime, EnumIncrType.Inventory);
                    if (hotelIncrIdResult != null) {
                        incrInvLastIdStr = String.valueOf(hotelIncrIdResult.getResult().getLastId());
                    }
                } else {
                    incrInvLastIdStr = incrInvLastIdObj.toString();
                }
                if (StringUtils.isNotEmpty(incrInvLastIdStr)) {
                    HotelIncrInvResult hotelIncrInvResult = httpStaticService.gethotelIncrInv(Long.valueOf(incrInvLastIdStr));
                    if (hotelIncrInvResult != null && "0".equals(hotelIncrInvResult.getCode())) {
                        List<IncrInventory> inctInvList = hotelIncrInvResult.getResult().getInventories();
                        if (inctInvList.size() > 0) {
                            // 库存增量列表保存到redis，设置10分钟有效期
                            redisTemplate.opsForValue().set(RedisConstant.REDIS_INCR_INV_L_KEY.replace("{lastid}", incrInvLastIdStr), inctInvList, 5, TimeUnit.MINUTES);
                            // 把当前lastId加到库存增量待更新队列
                            //redisTemplate.opsForList().leftPush(RedisConstant.REDIS_INCR_INV_UPDATE_LASTID_LIST_KEY, incrInvLastIdStr);
                            redisPublisherService.sendMessage(incrInvLastIdStr);

                            IncrInventory incrInventory = inctInvList.get(inctInvList.size() - 1);
                            incrInvLastIdStr = String.valueOf(incrInventory.getLastId());
                            lastTime = incrInventory.getTime();
                        }
                    }
                }

                incrInvLogger.info("完成艺龙国内酒店－库存增量生产者，当前时间：{}，一共耗时：{} ", DateUtil.format(new Date(), DateUtil.PATTERN_CLASSICAL), (System.currentTimeMillis() - start));
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 把最新的最后的更新缓存到redis
                if (StringUtils.isNotEmpty(incrInvLastIdStr) && lastTime != null) {
                    hotelInventoryService.updateIncrLastIdInfo(incrInvLastIdStr, lastTime);
                }
            }
        }
    }

    /**
     * 国内酒店-库存增量消费者
     */
    @Async("incrTaskExecutor")
    public void incrInvCustomer() {
        int updateSize = 5000;
        List<ElongHotelInventoryPO> updateInvPoList = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        while (true) {
            try {
                //incrInvLogger.info("启动艺龙国内酒店－库存增量消费者，开始时间：{} ", DateUtil.format(new Date(), DateUtil.PATTERN_CLASSICAL));
                long start = System.currentTimeMillis();
                // 队列获取增量库存待更新的id
                String invLastId = (String) redisTemplate.opsForList().rightPop(RedisConstant.REDIS_INCR_INV_UPDATE_LASTID_LIST_KEY);
                if (StringUtils.isNotEmpty(invLastId)) {
                    int updateInvPoListSize = 0;
                    updateInvPoList = new ArrayList<>();
                    // 获取增量库存更新id对应的更新记录
                    Object inctInvListObj = redisTemplate.opsForValue().get(RedisConstant.REDIS_INCR_INV_L_KEY.replace("{lastid}", invLastId));

                    if (inctInvListObj != null) {
                        List<IncrInventory> inctInvList = (List<IncrInventory>) inctInvListObj;

                        for (IncrInventory incrInventory : inctInvList) {
                            StringBuilder indexBuilder = new StringBuilder();
                            indexBuilder.append(incrInventory.getHotelID()).append("_")
                                    .append(incrInventory.getRoomTypeId()).append("_")
                                    .append(incrInventory.getHotelCode()).append("_")
                                    .append(sdf.format(incrInventory.getDate()));
                            int count = redisTemplate.hasKey(indexBuilder.toString()) == true ? 1 : 0;
                            if (count == 0) {
                                EntityWrapper<ElongHotelInventoryPO> ew = new EntityWrapper<>();
                                ew.where("hotel_id={0}", incrInventory.getHotelID())
                                        .and("room_type_id={0}", incrInventory.getRoomTypeId())
                                        .and("hotel_code={0}", incrInventory.getHotelCode())
                                        .and("date={0}", incrInventory.getDate());
                                count = elongHotelInventoryService.selectCount(ew);
                            }

                            if (count > 0) {
                                ElongHotelInventoryPO elongHotelInventoryPO = hotelInventoryService.getPoByInventory(incrInventory);
                                updateInvPoList.add(elongHotelInventoryPO);
                                updateInvPoListSize++;
                                if (updateInvPoListSize >= updateSize) {
                                    elongHotelInventoryService.updateBatch(updateInvPoList);
                                    updateInvPoList.clear();
                                    updateInvPoListSize = 0;
                                }
                            }
                        }
                        incrInvLogger.info("处理数据耗时：{} ", (System.currentTimeMillis() - start));

                        if (updateInvPoListSize > 0) {
                            elongHotelInventoryService.updateBatch(updateInvPoList);
                            incrInvLogger.info("入库耗时：{} ", (System.currentTimeMillis() - start));
                        }
                    }
                }

                //incrInvLogger.info("完成艺龙国内酒店－库存增量消费者，当前时间：{}，一共耗时：{} ", DateUtil.format(new Date(), DateUtil.PATTERN_CLASSICAL), (System.currentTimeMillis() - start));
                incrInvLogger.info("完成艺龙国内酒店－库存增量消费者，一共耗时：{} ", (System.currentTimeMillis() - start));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
